﻿using System;
using System.Collections.Concurrent;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;

public class TestThreadUIByThread : MonoBehaviour {

    public Button StartButton;
    public Button CancelButton;
    public Slider ValueSlider;
    public Text InfoText;

    void Start()
    {
        if (null != StartButton)
        {
            StartButton.onClick.AddListener(OnButtonStart);
            StartButton.interactable = true;
        }

        if (null != CancelButton)
        {
            CancelButton.onClick.AddListener(OnButtonCancel);
            CancelButton.interactable = false;
        }

        if (null != ValueSlider)
        {
            ValueSlider.minValue = 0;
            ValueSlider.maxValue = 100;
            ValueSlider.value = 0;
        }

        if (null != InfoText)
        {
            InfoText.text = "";
        }

    }
    CancellationTokenSource tokenSource = null;
    CancellationToken token;

    //使用并发集合来同步执行操作
    //必须使用.Net 4.x(Player Settings / Configruation)
    private ConcurrentQueue<Action> queueActionCallback = new ConcurrentQueue<Action>();
    private ConcurrentQueue<Action> queueActionCompleted = new ConcurrentQueue<Action>();

    Action action, actionCompleted;
    void Update () {
        while ( queueActionCallback.TryDequeue(out action) )
        {
            action();
        }

        while (queueActionCompleted.TryDequeue(out actionCompleted))
        {
            actionCompleted();
        }
    }

    void OnThreadCallback()
    {
        InfoText.text = msg;
        ValueSlider.value = count;
    }

    void OnThreadCompleted()
    {
        InfoText.text = "Work Completed.";

        ReadyToRestart();
    }

    void OnThreadCanceled()
    {
        InfoText.text = "Work Canceled.";        

        ReadyToRestart();
    }

    void ReadyToRestart()
    {
        StartButton.interactable = true;
        CancelButton.interactable = false;

        count = 0;
        msg = "";
    }

    int count = 0;
    string msg = "";
    void DoWork()
    {
        while (count <= 100)
        {
            if (token.IsCancellationRequested)
            {
                Debug.Log("Work Thread Canceled.");
                break;
            }

            msg = "Count : " + count;
            //Debug.Log(msg);

            //在这里访问主线程的UI内容，会报错
            //get_isActiveAndEnabled can only be called from the main thread.
            //InfoText.text = msg;

            //使用Action，将Action通知给主线程
            queueActionCallback.Enqueue(OnThreadCallback);

            Thread.Sleep(50);

            count++;
        }

        if (token.IsCancellationRequested)
        {
            //queueActionCompleted.Enqueue(OnThreadCanceled);//Right
            queueActionCompleted.Enqueue( () => {
                InfoText.text = "Work Canceled (Lambda).";
                ReadyToRestart();
            });
        }
        else
        {
            queueActionCompleted.Enqueue(OnThreadCompleted);
        }
    }

    public void OnButtonStart()
    {
        StartButton.interactable = false;
        CancelButton.interactable = true;

        tokenSource = new CancellationTokenSource();
        token = tokenSource.Token;

        Thread t = new Thread(DoWork);
        t.Start();
    }

    public void OnButtonCancel()
    {
        CancelWorker();
    }

    void CancelWorker()
    {
        if (null != tokenSource && !tokenSource.IsCancellationRequested)
        {
            tokenSource.Cancel();
            tokenSource.Dispose();
        }
    }

    #region 下列三种情况可以取消线程的运行
    private void OnDestroy()
    {
        Debug.Log("OnDestroy");

        CancelWorker();
    }
    #endregion
}
